#include "LCommon.h"

initSing(AccountManager);

static void ToUpper(char* txt)
{
	for(ui32 i = 0; i < strlen(txt); ++i)
	{
		txt[i] = toupper(txt[i]);
	}
}

void AccountManager::LoadAccounts()
{
	m_lock.Acquire();
	Log->Notice("AccountMgr", "Loading accounts...");
	m_accounts.clear();
	m_lock.Release();
	QResult* rs = LogonDb.SafeQuery("Select * from accounts");
	if(!rs)
	{
		Log->Notice("AccountMgr", "Error loading accounts! Check your accountdatabase!");
		return;
	}
	Account* acc;
	if(!rs->NumRows())
	{
		Log->Notice("AccountMgr", "Finished loading! 0 accounts can be used!");
		return;
	}
	do
	{
		acc = new Account();
		acc->id = rs->Fetch()[0];
		acc->username = rs->Fetch()[1];
		acc->gmstring = rs->Fetch()[4];
		if(!acc->username)
		{
			delete [] acc;
			continue;
		}
		ToUpper(acc->username);
		acc->passwordhash = (ui8*)(char*)rs->Fetch()[3];
		if(!acc->passwordhash)
		{
			char* pw = rs->Fetch()[2];
			ToUpper(pw);
			ScopedAllocator<char> tmp(100);
			sprintf(tmp, "%s:%s", acc->username, pw);
			printf("%s\n", tmp);
			Sha1Hash hash;
			hash.UpdateData((const ui8*)tmp, strlen(tmp));
			hash.Finalize();
			acc->passwordhash = new ui8[20];
			memcpy(acc->passwordhash, hash.GetDigest(), 20);
			tmp.Resize(41);
			for(int i = 0; i < 20; ++i)
			{
				sprintf(tmp + 2 * i, "%02x", acc->passwordhash[i]);
			}
			realloc(acc->passwordhash, 41);
			strcpy((char*)acc->passwordhash, tmp);
			LogonDb.Query("update accounts set password_hash = \"%s\" where accountid = %u", acc->passwordhash, (ui32)rs->Fetch()[0]);
		}
		m_lock.Acquire();
		m_accounts.insert(std::make_pair<const char*, Account*>(acc->username, acc));
		m_lock.Release();
	}
	while(rs->NextRow());

	Log->Notice("AccountMgr", "Finished loading! %u accounts can be used!", m_accounts.size());
}

Account* AccountManager::GetAccount(const char* name)
{
	m_lock.Acquire();
	std::map<const char*, Account*>::iterator ir = m_accounts.begin();
	std::map<const char*, Account*>::iterator end = m_accounts.end();
	for( ; ir != end; ++ir)
	{
		if(!strcmp(ir->first, name))
		{
			m_lock.Release();
			return ir->second;
		}
	}
	m_lock.Release();

	return NULL;
}

void AccountManager::AddAccount(const char* username, const char* passwd)
{
	ToUpper((char*)username);
	if(GetAccount(username))
	{
		Log->Notice("AccountMgr", "Account %s allready exists!", username);
		return;
	}
	Account* acc = new Account();
	acc->username = new char[strlen(username) + 1];
	memcpy(acc->username, username, strlen(username));
	acc->username[strlen(username)] = 0;
	ScopedAllocator<char> tmp(100);
	sprintf(tmp, "%s:%s", acc->username, passwd);
	Sha1Hash hash;
	hash.UpdateData((const ui8*)tmp, strlen(tmp));
	hash.Finalize();
	acc->passwordhash = new ui8[20];
	memcpy(acc->passwordhash, hash.GetDigest(), 20);
	tmp.Resize(41);
	for(int i = 0; i < 20; ++i)
	{
		sprintf(tmp + 2 * i, "%02x", acc->passwordhash[i]);
	}
	delete [] acc->passwordhash;
	acc->passwordhash = new ui8[41];
	strcpy((char*)acc->passwordhash, tmp);
	LogonDb.Query("Insert into accounts VALUES (NULL, \"%s\", \"%s\", \"%s\")", acc->username, passwd, acc->passwordhash);
	m_lock.Acquire();
	m_accounts.insert(std::make_pair<const char*, Account*>(acc->username, acc));
	m_lock.Release();
	Log->Notice("AccountMgr", "Account %s added!", acc->username);
}

void AccountWorker::Loop()
{
	ui32 lasttime = 0;
	refresh = logon_config->GetUInt("General Settings", "Refresh", 120);
	if(refresh < 10)
		refresh = 10;
	refresh *= 1000;
	while(ThreadState)
	{
		if(GetTickCount() - lasttime > refresh)
		{
			AccountMgr->LoadAccounts();
			lasttime = GetTickCount();
		}
		Sleep(2500);
	}
}